/*
 * ModuleDescription.java
 * 
 * last update: 16.01.2010 by Stefan Saru
 * 
 * author:	Alec(panovici@elcom.pub.ro)
 * 
 * Obs:
 */
package engine;

import java.util.*;
import middle.*;

/**
 * This contains the description of the inside structure of a module (regs, integers, 
 * threads of control, etc).
 * Its main purpose is to creatye all the instances needed inside a module ( which in turn
 * is created by ModuleInstanceDesscription.instantiate(..)).
 */
class ModuleDescription
extends UserModuleDescription
{

	/**
	 * The file that contains this module description.
	 */
	String fileName;

	/**
	 * The line at wich this module begins.
	 */
	int line;


	/**
	 * set if parameters have been set for this instantiation
	 * (this means that instantiateAll must undefine them
	 *  because recursive instantiation might re-use them)
	 * But I guess re-using 'em is possible only if a module
	 * is recursive instantiating itself...
	 */
	boolean setParams;


	ModuleDescription(String fileName, int line, String name){
		super(name);
		this.fileName = fileName;
		this.line = line;
		this.name = name;
	}

	public boolean isTop(){
		return !(VeriParser.instantiatedModules.contains(name));
	}  


	void instantiateAll(Module m, ScopeNode thisScope)throws ParseException{
		super.instantiateAll(m, thisScope);
	}

	/**
	 * Adds wires where not explicitely declared for ports.
	 */
	public void checkup() throws ParseException {
		for (Enumeration e = ports.elements() ; e.hasMoreElements() ;) {
			PortDescription p = (PortDescription)e.nextElement();
			if (regs.get(p.name) == null)
				addWire( p.name, p.lineNo, p.msbExp, p.lsbExp,
						WireDescription.defaultExpandType,
						WireDescription.defaultNetType,
						Delay3Description.nullDelay);
		}
	}

	/**
	 * Verifies that ports types and the corresponding data declarations
	 * work together (wire for input, etc.).
	 */
	void checkPorts(NameSpace ns) throws ParseException {
		for (Enumeration e = ports.elements() ; e.hasMoreElements() ; ) {
			PortDescription p = (PortDescription)e.nextElement();
			p.instantiate(ns, null);
			int nMsb, nLsb;
			Object o = ns.resolveNameExact(new FQN(p.name));
			try {
				Wire w = (Wire) o;
				try{
					p.checkRange(w.msb, w.lsb);
				} catch (ParseException pex){
					throw new ParseException(toString(p.lineNo) + pex);
				}
				continue;
			} catch (ClassCastException cex) {}
			try {
				Register r = (Register) o;
				if(r.isMemory())
					throw new ParseException(toString(p.lineNo) + ":error : ports cannot be memories");
				BitVector b = r.getData(0);
				try {
					p.checkRange(b.msb, b.lsb);
				} catch (ParseException pex) {
					throw new ParseException(toString(p.lineNo) + pex);
				}
				continue;
			} catch (ClassCastException cex) {
				throw new ParseException(toString(p.lineNo) + ":error : bad port data type");
			}
		}

	}

	public String toString(){
		return fileName + ":" + name;
	}

	public String toString(int line){
		return fileName + ":" + line + ":" + name;
	}

	public String getFileName(){
		return fileName;
	}


	///////////////////////////////
	// ModuleFactory implementation
	///////////////////////////////

	/**
	 * Makes the parameters to hold the right values for the
	 * current instantiation
	 */
	public void setParams (Vector results, Delay3 delays)
	throws ParseException
	{
		xConsole.debug("setting params:");
		if (setParams)  //recursive self-instantiation
			throw new ParseException(": error: recursive instantiation");

		if (delays != null)
			throw new ParseException(": error: modules cannot have delays specs");

		if(results == null)return;

		Enumeration ep, er;
		for (er = regsVector.elements(), ep = results.elements() ;
		ep.hasMoreElements() && er.hasMoreElements() ;) {
			try {
				ParameterDescription p = (ParameterDescription) er.nextElement();
				p.define((Result) ep.nextElement());
			} catch (ClassCastException ex) {};
		}
		if(ep.hasMoreElements())
			throw new ParseException(": error: too many parameter values supplied");
		setParams = true;
	}

	public void unsetParams () {
		for (Enumeration e = regsVector.elements(); e.hasMoreElements() ;) {
			try {
				ParameterDescription p = (ParameterDescription) e.nextElement();
				p.define(null);
			} catch (ClassCastException ex) {};
		}
		setParams = false;
	}

	/**
	 * @see ModuleFactory
	 */
	public Object createNewModule (NameSpace parent,
			ModuleInstanceDescription miDesc,
			byte strength,
			ScopeNode thisScope) throws ParseException{
		Module m = new Module(this, parent, miDesc, thisScope);
		linkModule (m, parent, strength, miDesc);
		return m;
	}

	public Object createNewModuleArray(NameSpace parent,
			ModuleInstanceDescription miDesc,
			byte strength,
			ScopeNode thisScope, int ars, int are,
			int n, int increment)
	throws ParseException
	{
		Module[] modules = new Module[n];
		for (int i = 0; i < n ; i++) {
			int index = ars + i * increment;
			modules[i] = new Module(this, parent, miDesc, index, 
					thisScope.addScope(Constants.plaIcon,
							name + "[" +
							         (index) +
							         "]"));
		}
		linkModuleArray(modules, parent, miDesc, strength,
				ars, are, n, increment);
		return new ModuleArray(this, parent, ars,
				are, n, increment, modules);
	}
}









